package com.nowcoder.topic.greedy.middle;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Stack;

/**
 * NC209 最短无序连续子数组
 * @author d3y1
 */
public class NC209{
    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int findUnsortedSubarray (int[] nums) {
        return solution1(nums);
//        return solution2(nums);
//        return solution3(nums);
//        return solution4(nums);
    }

    /**
     * 单调栈+贪心
     * @param nums
     * @return
     */
    private int solution1(int[] nums){
        int n = nums.length;

        // 方式1
        Stack<Integer> leftStack = new Stack<>();
        Stack<Integer> rightStack = new Stack<>();
        // 方式2
        // Deque<Integer> leftStack = new ArrayDeque<>();
        // Deque<Integer> rightStack = new ArrayDeque<>();
        // 方式3
        // Deque<Integer> leftStack = new LinkedList<>();
        // Deque<Integer> rightStack = new LinkedList<>();

        int left = Integer.MAX_VALUE;
        int right = 0;
        for(int i=0; i<n; i++){
            // 单调栈(单调增) 从左往右
            while(!leftStack.isEmpty() && nums[leftStack.peek()]>nums[i]){
                // 贪心
                left = Math.min(left, leftStack.pop());
            }
            leftStack.push(i);

            // 单调栈(单调减) 从右往左
            while(!rightStack.isEmpty() && nums[rightStack.peek()]<nums[n-i-1]){
                // 贪心
                right = Math.max(right, rightStack.pop());
            }
            rightStack.push(n-i-1);
        }

        return left==Integer.MAX_VALUE?0:right-left+1;
    }

    /**
     * 单调栈+贪心
     * @param nums
     * @return
     */
    private int solution2(int[] nums){
        int n = nums.length;

        Deque<Integer> leftStack = new ArrayDeque<>();
        Deque<Integer> rightStack = new ArrayDeque<>();

        int left = Integer.MAX_VALUE;
        int right = 0;
        for(int i=0; i<n; i++){
            // 单调栈(单调增) 从左往右
            while(!leftStack.isEmpty() && nums[leftStack.peekFirst()]>nums[i]){
                // 贪心
                left = Math.min(left, leftStack.pollFirst());
            }
            leftStack.offerFirst(i);

            // 单调栈(单调减) 从右往左
            while(!rightStack.isEmpty() && nums[rightStack.peekFirst()]<nums[n-i-1]){
                // 贪心
                right = Math.max(right, rightStack.pollFirst());
            }
            rightStack.offerFirst(n-i-1);
        }

        return left==Integer.MAX_VALUE?0:right-left+1;
    }

    /**
     * 单调栈+贪心
     * @param nums
     * @return
     */
    private int solution3(int[] nums){
        int n = nums.length;

        Deque<Integer> leftStack = new LinkedList<>();
        Deque<Integer> rightStack = new LinkedList<>();

        int left = Integer.MAX_VALUE;
        int right = 0;
        for(int i=0; i<n; i++){
            // 单调栈(单调增) 从左往右
            while(!leftStack.isEmpty() && nums[leftStack.peekLast()]>nums[i]){
                // 贪心
                left = Math.min(left, leftStack.pollLast());
            }
            leftStack.offerLast(i);

            // 单调栈(单调减) 从右往左
            while(!rightStack.isEmpty() && nums[rightStack.peekLast()]<nums[n-i-1]){
                // 贪心
                right = Math.max(right, rightStack.pollLast());
            }
            rightStack.offerLast(n-i-1);
        }

        return left==Integer.MAX_VALUE?0:right-left+1;
    }

    /**
     * 双指针+贪心
     * @param nums
     * @return
     */
    private int solution4(int[] nums){
        int n = nums.length;

        int left = Integer.MAX_VALUE;
        int right = 0;
        int min = nums[n-1];
        int max = nums[0];
        for(int i=1; i<n; i++){
            // min(nums[n-i-1,n-1])
            min = Math.min(min, nums[n-i-1]);
            // max(nums[0,i])
            max = Math.max(max, nums[i]);
            // 贪心 从右往左
            if(nums[n-i-1] != min){
                left = n-i-1;
            }
            // 贪心 从左往右
            if(nums[i] != max){
                right = i;
            }
        }

        return left==Integer.MAX_VALUE?0:right-left+1;
    }
}